local ActionType  = require("excel.Skill").ActionType
local FixPosition = require("skill.FixPosition")
local Scan      = require("skill.Scan")
local Skill     = require("skill.Skill")
local Utilitys    = require("skill.Utilitys")
local SkillExcel  = require("excel.Skill").Skill
local Conditions  = require("skill.Conditions")
local SkillDefine = require("skill.Define")
local Util        = require("common.Util")
local Obj         = require("core.Obj")
local Notify      = require("skill.Notify")
local AOE_TYPE_ROUND        = Scan.AOE_TYPE_ROUND
local ACTTACK_TYPE_SELF       = SkillDefine.ACTTACK_TYPE_SELF
local ACTION_TYPE_BESSEL_REVERSE  = SkillDefine.ACTION_TYPE_BESSEL_REVERSE


local MAX_POOL_NUM =30000

if not pool then
    pool = {}
    for k=1, MAX_POOL_NUM do
        pool[k] = {}
    end
end

function getInstance()
    local unit = pool[#pool]
    if unit then
        pool[#pool] = nil
        unit.onEnd  = onEnd
        unit.onStart= onStart
        return unit
    end
    unit  = {}
    unit.onEnd  = onEnd
    unit.onStart= onStart
    return unit
end

-- 销毁
function destroy(unit)
     if #pool < MAX_POOL_NUM then
         pool[#pool+1] = unit
         unit.utilityConfig = nil
         unit.utilityArgs = nil
     end
end

--*************** 技能 作用单元 ****************

-- 克隆
function clone(node)
    local unit = getInstance()

    --
    unit.skillID    = node.skillID
    unit.utilityIndex = node.utilityIndex
    unit.utilityID    = node.utilityID
    unit.utilityConfig  = node.utilityConfig
    unit.utilityArgs  = node.utilityArgs
    unit.sceneID    = node.sceneID
    unit.id       = node.id
    unit.uid      = node.uid
    unit.level      = node.level
    unit.mouseX     = node.mouseX
    unit.mouseY     = node.mouseY
    unit.tx       = node.tx
    unit.ty       = node.ty
    unit.x        = node.x
    unit.y        = node.y
    unit.dir      = node.dir
    unit.tid      = node.tid
    unit.tuid     = node.tuid

    unit.delayFlyTime = 0 -- 延迟飞行时间
    unit.flag     = false -- 用于标记特殊判断

    unit.createTime = node.createTime
    FixPosition.fixActionType(unit) -- 修正特殊actionType 坐标位置

    return unit
end

-- 发动
function onStart(unit)
    unit.run = false
    local delayFlyTime = unit.delayFlyTime
    if delayFlyTime>0 then
        Skill.timer:insert(unit.delayFlyTime, unit)
    else
        local x, y        = unit.x, unit.y
        local utilityConfig    = unit.utilityConfig
        local actionTypeConfig   = ActionType[utilityConfig.actionType]
        local obj     = Obj.getObj(unit.id,  unit.uid)
        if not obj then
            destroy(unit)   --施法者已消失
            return
        end
        if (utilityConfig.actionType == ACTION_TYPE_BESSEL_REVERSE and utilityConfig.hitID~=0)
            or actionTypeConfig.specialFly == 1
            or (actionTypeConfig.normalFly == 1 and utilityConfig.flyID~=0 ) then
            local skillConfig   = SkillExcel[unit.skillID]
            local target      = Obj.getObj(unit.tid, unit.tuid)
            Notify.GC_SKILL_MAGIC_FLY(obj, unit.sceneID, unit.skillID, skillConfig, unit.utilityConfig, unit.tx, unit.ty, x, y, target)
        end

        if utilityConfig.acttackCenter == ACTTACK_TYPE_SELF and utilityConfig.aoeType == AOE_TYPE_ROUND then
            unit.tx, unit.ty = x, y
        end

        if unit.delay > 0 then
            Skill.timer:insert(unit.delay, unit)
        else
            onEnd(unit)
        end
    end
end

-- 到达
function onEnd(unit)
    if unit.run then -- 上次报错过
        return
    end

    unit.run = true

    -- 延迟飞行结束 开始飞行
    if unit.delayFlyTime >0 then
        unit.delayFlyTime = 0
        onStart(unit)

    else --到达目的地       
        utility(unit) -- 生效作用
        destroy(unit)
    end
end

-- 生效作用
function utility(unit)
    local id, uid = unit.id, unit.uid
    local obj = Obj.getObj(id, uid)
    if not obj then
        return
    end -- 施法者不存在

    local x, y, tx, ty, tid, tuid = unit.x, unit.y, unit.tx, unit.ty, unit.tid, unit.tuid
    local utilityConfig    = unit.utilityConfig
    local actionTypeConfig   = ActionType[utilityConfig.actionType]
    local bombID       = utilityConfig.bombID

    if actionTypeConfig and (actionTypeConfig.specialBomb == 1) or (utilityConfig.actionType == ACTION_TYPE_BESSEL_REVERSE and utilityConfig.bombID~=0)
        or (actionTypeConfig.normalBomb == 1 and bombID ~= 0) then
        local skillConfig   = SkillExcel[unit.skillID]
        local target      = Obj.getObj(tid,  tuid)
        Notify.GC_SKILL_BOMB(obj, unit.sceneID, unit.skillID,  skillConfig, unit.utilityConfig, tx, ty, x, y, target)
    end

    local bombQuake   = utilityConfig.bombQuake
    local space     = utilityConfig.space
    if not ( (#bombQuake<1 or bombQuake[1]<1) and space<1  and ((not bombQuake[3] or bombQuake[3]==1))  ) then
        Notify.GC_SKILL_SPECIAL(obj, unit.sceneID, unit.utilityConfig, tx, ty, x, y)
    end

    local target      = Obj.getObj(unit.tid, unit.tuid)
    local aoeType     = utilityConfig.aoeType
    local maxCount      = utilityConfig.aoeNum
    local isPriorityTarget  = aoeType==AOE_TYPE_ROUND and target and maxCount and maxCount>1
    local arg1        = utilityConfig.aoeArgs[1]
    local arg2        = utilityConfig.aoeArgs[2]
    local conditionFunc   = Conditions.special

    if isPriorityTarget then  --如果有目标 优先攻击目标
        Scan.data[1]      = arg1
        Scan.data.conditionFunc = conditionFunc
        if Scan.round(obj, target, unit) then
            conditionFunc = conditionNotTarget
            maxCount    = maxCount - 1
            Utilitys.handle(obj, target, unit)
        end
    end

    Scan.handle(aoeType, obj, target, unit, Utilitys.handle, conditionFunc, maxCount>0 and maxCount or nil, arg1, arg2)
end

function conditionNotTarget(obj, target, unit)
    return Obj.getObj(unit.tid, unit.tuid)~=target and Conditions.special(obj, target, unit)
end



local dist2 = Util.dist2
local dist  = Util.dist

-- 计算总飞行时间
function calcFlyTime(unit)
    local utilityConfig = unit.utilityConfig
    local flySpeed    = utilityConfig.flySpeed
    if flySpeed<1 then return 0 end -- 如果飞向速度为0的话 那么立即击中

    local actionType = utilityConfig.actionType
    local len

    if actionType == SkillDefine.ACTION_TYPE_FALL then
        local tx, ty = unit.tx, unit.ty
        len = dist(tx, ty - utilityConfig.actionArg[1], tx, ty)
    elseif actionType == SkillDefine.ACTION_TYPE_CENTER_BLOMB then
        len = utilityConfig.actionArg[1]
    else
        local actionTypeConfig = ActionType[actionType]
        local x, y, tx, ty  = unit.x, unit.y, unit.tx, unit.ty
        if actionTypeConfig.normalFly==1 and utilityConfig.flyID~=0 then
            len = dist2(x, y, tx, ty)
        else
            len = dist(x, y, tx, ty)
        end
    end

    return len/flySpeed*1000
end
